package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.repository;

import com.iwhalecloud.citybrain.flow.platform.manager.application.service.NodeCandidateService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.ExpressionCmd;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ResponseResult;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowTaskVariableService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics;
import org.flowable.bpmn.model.SubProcess;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.common.api.variable.VariableContainer;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode.PARAMETER_ERROR;
import static com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode.PARAM_NOT_EXIST;

/**
 * @author: liyang
 * @date: 2021/12/15 19:29
 */
@Slf4j
@Service
public class FlowTaskVariableServiceImpl implements FlowTaskVariableService {

    @Autowired
    private NodeCandidateService nodeCandidateService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ManagementService managementService;

    @Autowired
    private RuntimeService runtimeService;

    @Override
    public Object getTaskVariableByTaskIdAndKey(String taskId, String key) {

        if (Objects.isNull(taskId) || Objects.isNull(key)) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), PARAM_NOT_EXIST.errMessage());
        }

        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (Objects.isNull(task)) {
            return ResponseResult.fail(PARAMETER_ERROR.errCode(), "根据taskId查询不到任务");
        }

        String currentExecutionId = nodeCandidateService.getCurrentExecutionId(task);
        ExecutionEntity executionEntity = nodeCandidateService.getSubProcessInstanceExecution(currentExecutionId);
        //如果不为空，则是子流程中的节点
        if (Objects.nonNull(executionEntity)) {
            FlowElement flowElement = repositoryService.getBpmnModel(executionEntity.getProcessDefinitionId()).getFlowElement(executionEntity.getActivityId());
            SubProcess subProcess = (SubProcess) flowElement;
            MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = subProcess.getLoopCharacteristics();
            if (Objects.nonNull(multiInstanceLoopCharacteristics)) {
                String elementVar = multiInstanceLoopCharacteristics.getElementVariable();
                if (StringUtils.isNotBlank(elementVar)) {
                    key = elementVar + "." + key;
                }
            }
        }
        String expression = "${" + key + "}";
        if (Objects.nonNull(executionEntity)) {
            return getValueFromEntity(expression, executionEntity);
        } else {
            return getValueFromEntity(expression, (TaskEntity) task);
        }
    }

    @Override
    public Object getVariableByProcessIdAndKey(String processInstanceId, String key) {

        if (Objects.isNull(processInstanceId) || Objects.isNull(key)) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), PARAM_NOT_EXIST.errMessage());
        }

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).active().singleResult();
        if (Objects.isNull(processInstance)) {
            return ResponseResult.fail(PARAMETER_ERROR.errCode(), "根据processInstanceId查询不到流程实例务");
        }
        Object processVariable = runtimeService.getVariable(processInstanceId, key);
        return processVariable;
    }

    public Object getValueFromEntity(String expression, VariableContainer variableContainer) {
        ExpressionCmd expressionCmd = new ExpressionCmd(expression, variableContainer);
        Object value = null;
        try {
            value = managementService.executeCommand(expressionCmd);
        } catch (Exception e) {
            log.error("getVariableValueError:", e);
        }
        return value;
    }


}
